package org.nativejpa.datasource;

import com.atomikos.jdbc.AtomikosDataSourceBean;
import com.atomikos.jdbc.AtomikosSQLException;
import com.atomikos.jdbc.nonxa.AtomikosNonXADataSourceBean;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.nativejpa.parser.PersistenceUnit;

import javax.sql.DataSource;
import javax.transaction.TransactionManager;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author <a href="mailto:jfox.young@gmail.com">Young Yang</a>
 * @create 2009-3-24 16:56:29
 */
public class AtomikosNonXADataSourceFactory extends DataSourceFactory {

    private static Map<String, DataSource> datasources = new HashMap<String, DataSource>(3);
    private static List<DataSource> dataSourceCount = new ArrayList<DataSource>(3);

    private static Log log = LogFactory.getLog(AtomikosNonXADataSourceFactory.class);

    public String getVendor() {
        return "Atomikos";
    }

    public DataSource createDataSource(PersistenceUnit persistenceUnit, TransactionManager transactionManager) {
        String key = persistenceUnit.getUnitName() + "_" + persistenceUnit.hashCode();
        if (!datasources.containsKey(key)) { // share one datasource when create many EntityManagerFactory with one persistence unit
            AtomikosNonXADataSourceBean ds = new AtomikosNonXADataSourceBean();
            ds.setUniqueResourceName(key);
            ds.setDriverClassName(persistenceUnit.getDataSourceJdbcDriver());
            ds.setUrl(persistenceUnit.getDataSourceJdbcURL());
            ds.setUser(persistenceUnit.getDataSourceJdbcUsername());
            ds.setPassword(persistenceUnit.getDataSourceJdbcPassword());

            try {
                ds.setLoginTimeout(120);
            }
            catch (SQLException e) {
                e.printStackTrace();
            }
            ds.setBorrowConnectionTimeout(persistenceUnit.getDataSourcePoolConnectTimeout()); // default 30s
            ds.setMaintenanceInterval(120); // default 60s
            ds.setMaxIdleTime((int) persistenceUnit.getDataSourcePoolMaxIdleTime());
            ds.setPoolSize(10); // default min = max = 50
            ds.setMinPoolSize(persistenceUnit.getDataSourcePoolMinSize());
            ds.setMaxPoolSize(persistenceUnit.getDataSourcePoolMaxSize());
            ds.setReapTimeout(0); // no timeout
            if (persistenceUnit.getDataSourcePoolTestQuery() != null && !persistenceUnit.getDataSourcePoolTestQuery().trim().equals("")) {
                ds.setTestQuery(persistenceUnit.getDataSourcePoolTestQuery());
            }
            try {
                ds.init();
            }
            catch (AtomikosSQLException e) {
                throw new DataSourceException("Failed to init data source: " + ds.getUniqueResourceName(), e);
            }
            datasources.put(persistenceUnit.getUnitName(), ds);
        }
        DataSource dataSource = datasources.get(persistenceUnit.getUnitName());
        dataSourceCount.add(dataSource); // add to count
        return dataSource;
    }

    public void shutdownDataSource(DataSource dataSource) {
        dataSourceCount.remove(dataSource);
        if (!dataSourceCount.contains(dataSource)) { // no more EntityManagerFactory uses this dataSource, close it
            String key = ((AtomikosDataSourceBean) dataSource).getUniqueResourceName();
            datasources.remove(key);
            ((AtomikosDataSourceBean) dataSource).close();
        }
    }
}